﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

using openSourceC.Daylife;

namespace openSourceC.DaylifeClient
{
	/// <summary>
	///		Summary description for DayPIClient.
	/// </summary>
	//[DebuggerStepThrough()]
	public class DayPIClient
	{
		private Dictionary<string, Request> _requestQueue;


		#region Constructors

		/// <summary>
		///		Class constructor.
		/// </summary>
		public DayPIClient()
			: this(
				DaylifeSection.Instance.AccessKey,
				DaylifeSection.Instance.SharedSecret,
				DaylifeSection.Instance.SourceFilterId
			) { }

		/// <summary>
		///		Class constructor.
		/// </summary>
		/// <param name="accessKey">The access key.</param>
		/// <param name="sharedSecret">The shared secret.</param>
		/// <param name="sourceFilterId">The source filter Id. (optional)</param>
		public DayPIClient(string accessKey, string sharedSecret, string sourceFilterId = null)
		{
			AccessKey = accessKey;
			SharedSecret = sharedSecret;
			SourceFilterId = sourceFilterId;
		}

		#endregion

		#region Public Properties

		/// <summary>Gets or sets the access key.</summary>
		public string AccessKey { get; set; }

		/// <summary>Gets or sets the shared secret.</summary>
		public string SharedSecret { get; set; }

		/// <summary>Gets the number of items in the request quest</summary>
		public int RequestQueueCount
		{
			get { return (_requestQueue == null ? 0 : _requestQueue.Count); }
		}

		/// <summary>Gets or sets the source filter Id.</summary>
		public string SourceFilterId { get; set; }

		#endregion

		#region Private Properties

		private string BaseApiAddress
		{
			get
			{
				if (string.IsNullOrEmpty(DaylifeSection.Instance.BaseApiAddress))
				{
					throw new ApplicationException("BaseApiAddress is null or empty.");
				}

				string value = DaylifeSection.Instance.BaseApiAddress;

				return (value != null && value.EndsWith("/") ? value.Substring(0, value.Length - 1) : value);
			}
		}

		private string BatchApiPath
		{
			get
			{
				if (string.IsNullOrEmpty(DaylifeSection.Instance.BatchApiPath))
				{
					throw new ApplicationException("BatchApiPath is null or empty.");
				}

				StringBuilder stringBuilder = new StringBuilder(DaylifeSection.Instance.BatchApiPath);

				if (stringBuilder[0] != '/') { stringBuilder.Insert(0, '/'); }
				if (stringBuilder[stringBuilder.Length - 1] != '/') { stringBuilder.Append('/'); }

				return stringBuilder.ToString();
			}
		}

		private string PublicApiPath
		{
			get
			{
				if (string.IsNullOrEmpty(DaylifeSection.Instance.PublicApiPath))
				{
					throw new ApplicationException("PublicApiPath is null or empty.");
				}

				StringBuilder stringBuilder = new StringBuilder(DaylifeSection.Instance.PublicApiPath);

				if (stringBuilder[0] != '/') { stringBuilder.Insert(0, '/'); }
				if (stringBuilder[stringBuilder.Length - 1] != '/') { stringBuilder.Append('/'); }

				return stringBuilder.ToString();
			}
		}

		private Dictionary<string, Request> RequestQueue
		{
			get
			{
				if (_requestQueue == null)
				{
					_requestQueue = new Dictionary<string, Request>();
				}

				return _requestQueue;
			}
		}

		#endregion

		#region Public Methods

		/// <summary>
		///		Adds a <see cref="Request"/> to the request queue.
		/// </summary>
		/// <param name="requestId">The request identifier.</param>
		/// <param name="request">The <see cref="Request"/> to use.</param>
		public void AddRequestToQueue(string requestId, Request request)
		{
			request.AppendParameter("request_id", false, requestId);

			RequestQueue.Add(requestId, request);
		}

		/// <summary>
		///		Clears the request queue.
		/// </summary>
		public void ClearQueue()
		{
			_requestQueue = null;
		}

		/// <summary>
		///		Gets a <see cref="Response"/> for the given <see cref="Request"/>.
		/// </summary>
		/// <param name="request">The <see cref="Request"/> to use.</param>
		/// <returns>
		///		A <see cref="Response"/> object.
		/// </returns>
		public Response GetResponse(Request request)
		{
			UriBuilder requestUri = new UriBuilder(BaseApiAddress + PublicApiPath + request.MethodName);
			requestUri.Query = request.GetQueryString();

			HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri.Uri);
			HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();

			using (Stream stream = webResponse.GetResponseStream())
			{
				XmlSerializer serializer = new XmlSerializer(typeof(Response));
				return (Response)serializer.Deserialize(stream);
			}
		}

		/// <summary>
		///		Processes the first 12 request objects in the queue, executing them from a batch
		///		call, and returning a <see cref="Response"/> object.  Each request is executed in
		///		parallel on the Daylife servers and removed from the queue upon successful
		///		completion of the batch call.
		/// </summary>
		/// <param name="timeout">The timeout value in seconds.  Default is 25 seconds. (optional)</param>
		/// <returns>
		///		A <see cref="BatchResponse"/> object.
		/// </returns>
		public BatchResponse ProcessQueue(int? timeout = null)
		{
			if (_requestQueue == null || _requestQueue.Count == 0)
			{
				throw new InvalidOperationException("The request queue is empty.");
			}

			StringBuilder queryString = new StringBuilder();
			queryString.AppendQueryStringPair("accesskey", AccessKey);
			if (timeout.HasValue) { queryString.AppendQueryStringPair("timeout", timeout.Value.ToString()); }

			List<KeyValuePair<string, Request>> requestQueueTake = _requestQueue.Take(12).ToList();

			foreach (KeyValuePair<string, Request> pair in requestQueueTake)
			{
				queryString.AppendQueryStringPair("request", PublicApiPath + pair.Value.MethodName + '?' + pair.Value.GetQueryString());
			}

			UriBuilder requestUri = new UriBuilder(BaseApiAddress + BatchApiPath + "parallel");
			requestUri.Query = queryString.ToString();

			HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri.Uri);
			HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
			BatchResponse ro;

			using (Stream stream = webResponse.GetResponseStream())
			{
				XmlSerializer serializer = new XmlSerializer(typeof(BatchResponse));
				ro = (BatchResponse)serializer.Deserialize(stream);
			}

			ro.Responses = new List<BatchPayloadResponse>();

			foreach (XmlElement payload in ro.Payloads)
			{
				using (StringReader stringReader = new StringReader(payload.InnerXml))
				{
					XmlSerializer serializer = new XmlSerializer(typeof(BatchPayloadResponse));
					ro.Responses.Add((BatchPayloadResponse)serializer.Deserialize(stringReader));
				}
			}

			foreach (KeyValuePair<string, Request> pair in requestQueueTake)
			{
				_requestQueue.Remove(pair.Key);
			}

			return ro;
		}

		#endregion

		#region Article Calls

		/// <summary>
		///		Retrieves information for the specified list of articles.
		/// </summary>
		/// <param name="article">The list of articles.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="include_image">Return one related scraped image.</param>
		/// <param name="include_scores">Return enhanced score data for every article, if available.</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestArticle_GetInfo(
			IEnumerable<string> article,
			ArticleSearchByEnum searchType,
			bool? include_image,
			bool? include_scores
		)
		{
			Request request = new Request("article_getInfo", AccessKey, SharedSecret);
			request.AppendParameter(searchType == ArticleSearchByEnum.ArticleId ? "article_id" : "url", true, article);
			request.AppendParameter("include_image", false, include_image);
			request.AppendParameter("include_scores", false, include_scores);

			return request;
		}

		/// <summary>
		///		Retrieves quotes from within the specified list of articles.
		/// </summary>
		/// <param name="article">The list of articles.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="require_speaker">The quotes returned must have a known speaker. (optional)</param>
		/// <param name="speaker_topic_id">The list of topics that the quotes must be attributed to. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestArticle_GetQuotes(
			IEnumerable<string> article,
			ArticleSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			bool? require_speaker,
			IEnumerable<string> speaker_topic_id
		)
		{
			Request request = new Request("article_getQuotes", AccessKey, SharedSecret);
			request.AppendParameter(searchType == ArticleSearchByEnum.ArticleId ? "article_id" : "url", true, article);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("require_speaker", false, require_speaker);
			request.AppendParameter("speaker_topic_id", false, speaker_topic_id);

			return request;
		}

		/// <summary>
		///		Retrieves articles that are related to the specified list of articles.
		/// </summary>
		/// <param name="article">The list of articles.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="threshold">The minimum topic relevance score for returned item (1 to 9).</param>
		/// <param name="block_nsfw">Block obscene content. (optional)</param>
		/// <param name="source_blacklist">The list of sources to exclude.</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="include_image">Return one related scraped image.</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestArticle_GetRelatedArticles(
			IEnumerable<string> article,
			ArticleSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			byte? threshold,
			bool? block_nsfw,
			IEnumerable<string> source_blacklist,
			IEnumerable<string> source_whitelist,
			bool? include_image
		)
		{
			Request request = new Request("article_getRelatedArticles", AccessKey, SharedSecret);
			request.AppendParameter(searchType == ArticleSearchByEnum.ArticleId ? "article_id" : "url", true, article);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("threshold", false, threshold);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		/// <summary>
		///		Retrieves topics from within the specified list of articles.
		/// </summary>
		/// <param name="article">The list of articles.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="include_topic_type">Comma seperated list of topic types to include. (optional)</param>
		/// <param name="include_image">Return one thumbnail image for each topic. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestArticle_GetTopics(
			IEnumerable<string> article,
			ArticleSearchByEnum searchType,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string include_topic_type,
			bool? include_image
		)
		{
			Request request = new Request("article_getTopics", AccessKey, SharedSecret);
			request.AppendParameter(searchType == ArticleSearchByEnum.ArticleId ? "article_id" : "url", true, article);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("include_topic_type", false, include_topic_type);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		#endregion

		#region Content Calls

		/// <summary>
		///		Retrieves articles that contain the specified topic name.
		/// </summary>
		/// <param name="content">The text to extract topics from. Core input for generating the
		///		signature for this call.  Can contain up to 20,000 characters.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="threshold">Minimum article-article relevance score for returned item. If
		///		you are using sort=date, recommend using threshold=3 and higher (0 to 10). (optional)</param>
		/// <param name="block_nsfw">Flag to indicate if content scored as obscene should be blocked. (optional)</param>
		/// <param name="source_blacklist">The list of sources to exclude. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="include_image">Return one related scraped image. (optional)</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestContent_GetRelatedArticles(
			string content,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			int? threshold,
			bool? block_nsfw,
			IEnumerable<string> source_blacklist,
			IEnumerable<string> source_whitelist,
			bool? include_image
		)
		{
			Request request = new Request("content_getRelatedArticles", AccessKey, SharedSecret);
			request.AppendParameter("content", true, content);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("threshold", false, threshold);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		/// <summary>
		///		Retrieves topics that are mentioned in the given piece of text.
		/// </summary>
		/// <param name="content">The text to extract topics from. Core input for generating the
		///		signature for this call.  Can contain up to 20,000 characters.</param>
		/// <param name="link_content">Return content with links to topics embedded within the content. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="link_prefix">Base URL to prefix when embedding links to topics in the content. (optional)</param>
		/// <param name="include_topic_type">Comma seperated list of topic types to include. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestContent_GetTopics(
			string content,
			bool? link_content,
			int? limit,
			string link_prefix,
			IEnumerable<string> include_topic_type
		)
		{
			Request request = new Request("content_getTopics", AccessKey, SharedSecret);
			request.AppendParameter("content", true, content);
			request.AppendParameter("link_content", false, link_content);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("link_prefix", false, link_prefix);
			request.AppendParameter("include_topic_type", false, include_topic_type);

			return request;
		}

		#endregion

		#region Image Calls

		/// <summary>
		///		Retrieves basic information for the specified image identifier.
		/// </summary>
		/// <param name="image_id">The image identifier.</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestImage_GetInfo(
			string image_id,
			string source_filter_id
		)
		{
			Request request = new Request("image_getInfo", AccessKey, SharedSecret);
			request.AppendParameter("image_id", true, image_id);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);

			return request;
		}

		/// <summary>
		///		Retrieves topics from within the specified image identifier.
		/// </summary>
		/// <param name="image_id">The image identifier.</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="include_topic_type">Comma seperated list of topic types to include. (optional)</param>
		/// <param name="include_image">Return one thumbnail image for each topic. (optional)</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestImage_GetTopics(
			string image_id,
			string source_filter_id,
			int? limit,
			int? offset,
			string include_topic_type,
			bool? include_image
		)
		{
			Request request = new Request("image_getTopics", AccessKey, SharedSecret);
			request.AppendParameter("image_id", true, image_id);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter("include_topic_type", false, include_topic_type);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		#endregion

		#region Quote Calls

		/// <summary>
		///		Retrieves basic information for the specified quote.
		/// </summary>
		/// <param name="quote_id">The quote identifier.</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestQuote_GetInfo(
			string quote_id
		)
		{
			Request request = new Request("quote_getInfo", AccessKey, SharedSecret);
			request.AppendParameter("quote_id", true, quote_id);

			return request;
		}

		/// <summary>
		///		Retrieves topics from articles that are related to the article containing the specified quote.
		/// </summary>
		/// <param name="quote_id">The quote identifier.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="include_topic_type">Comma seperated list of topic types to include. (optional)</param>
		/// <param name="include_image">Return one thumbnail image for each topic. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestQuote_GetRelatedTopics(
			string quote_id,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			string include_topic_type,
			bool? include_image
		)
		{
			Request request = new Request("quote_getRelatedTopics", AccessKey, SharedSecret);
			request.AppendParameter("quote_id", true, quote_id);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("include_topic_type", false, include_topic_type);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		#endregion

		#region Search Calls

		/// <summary>
		///		Retrieves the number of references in the new of the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetCounts(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			string source_filter_id,
			IEnumerable<string> source_whitelist
		)
		{
			Request request = new Request("search_getCounts", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);

			return request;
		}

		/// <summary>
		///		Retrieves references to Daylife sources whose names match the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetMatchingSources(
			string query,
			int? limit,
			int? offset
		)
		{
			Request request = new Request("search_getMatchingSources", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);

			return request;
		}

		/// <summary>
		///		Retrieves references to Daylife topics whose names match the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="include_topic_type">Comma seperated list of topic types to include. (optional)</param>
		/// <param name="include_image">Return one thumbnail image for each topic. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetMatchingTopics(
			string query,
			int? limit,
			int? offset,
			string include_topic_type,
			bool? include_image
		)
		{
			Request request = new Request("search_getMatchingTopics", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter("include_topic_type", false, include_topic_type);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		/// <summary>
		///		Retrieves quotes that mention the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="block_nsfw">Block obscene content. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="source_blacklist">The list of Daylife source ids to exclude from returned results. (optional)</param>
		/// <param name="require_speaker">The quotes returned must have a known speaker. (optional)</param>
		/// <param name="speaker_topic_id">The list of topics that the quotes must be attributed to. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetQuotesAbout(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SearchSortByEnum? sort,
			string source_filter_id,
			bool? block_nsfw,
			IEnumerable<string> source_whitelist,
			IEnumerable<string> source_blacklist,
			bool? require_speaker,
			IEnumerable<string> speaker_topic_id
		)
		{
			Request request = new Request("search_getQuotesAbout", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SearchSortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("require_speaker", false, require_speaker);
			request.AppendParameter("speaker_topic_id", false, speaker_topic_id);

			return request;
		}

		/// <summary>
		///		Retrieves quotes that are said by the topic matching the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetQuotesBy(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SearchSortByEnum? sort,
			string source_filter_id,
			IEnumerable<string> source_whitelist
		)
		{
			Request request = new Request("search_getQuotesBy", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SearchSortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);

			return request;
		}

		/// <summary>
		///		Retrieves articles that containt the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="block_nsfw">Block obscene content. (optional)</param>
		/// <param name="source_blacklist">The list of sources to exclude.</param>
		/// <param name="has_image">Return only articles with associated images.</param>
		/// <param name="include_scores">Return enhanced score data for every article, if available.</param>
		/// <param name="sliding_excerpt">Suppress sliding excerpts.</param>
		/// <param name="include_image">Return one related scraped image.</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetRelatedArticles(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SearchSortByEnum? sort,
			string source_filter_id,
			IEnumerable<string> source_whitelist,
			bool? block_nsfw,
			IEnumerable<string> source_blacklist,
			bool? has_image,
			bool? include_scores,
			bool? sliding_excerpt,
			bool? include_image
		)
		{
			Request request = new Request("search_getRelatedArticles", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SearchSortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("has_image", false, has_image);
			request.AppendParameter("include_scores", false, include_scores);
			request.AppendParameter("sliding_excerpt", false, sliding_excerpt);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		/// <summary>
		///		Retrieves images related to articles that contain the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetRelatedImages(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SearchSortByEnum? sort,
			string source_filter_id
		)
		{
			Request request = new Request("search_getRelatedImages", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SearchSortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);

			return request;
		}

		/// <summary>
		///		Retrieves quotes from articles that contain the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="block_nsfw">Flag to indicate if content scored as obscene should be blocked. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="source_blacklist">The list of Daylife source ids to exclude from returned results. (optional)</param>
		/// <param name="require_speaker">The quotes returned must have a known speaker. (optional)</param>
		/// <param name="speaker_topic_id">The list of topics that the quotes must be attributed to. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetRelatedQuotes(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SearchSortByEnum? sort,
			string source_filter_id,
			bool? block_nsfw,
			IEnumerable<string> source_whitelist,
			IEnumerable<string> source_blacklist,
			bool? require_speaker,
			IEnumerable<string> speaker_topic_id
		)
		{
			Request request = new Request("search_getRelatedQuotes", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SearchSortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("require_speaker", false, require_speaker);
			request.AppendParameter("speaker_topic_id", false, speaker_topic_id);

			return request;
		}

		/// <summary>
		///		Retrieves references to Daylife topics that have appeared in articles containing
		///		the given query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="source_blacklist">The list of Daylife source ids to exclude from returned results. (optional)</param>
		/// <param name="include_topic_type">Comma seperated list of topic types to include. (optional)</param>
		/// <param name="include_image">Return one thumbnail image for each topic. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetRelatedTopics(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SearchSortByEnum? sort,
			string source_filter_id,
			IEnumerable<string> source_whitelist,
			IEnumerable<string> source_blacklist,
			string include_topic_type,
			bool? include_image
		)
		{
			Request request = new Request("search_getRelatedTopics", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SearchSortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("include_topic_type", false, include_topic_type);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		/// <summary>
		///		Retrieves videos related to articles that contain the specified query term.
		/// </summary>
		/// <param name="query">The search term.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="source_blacklist">The list of sources to exclude.</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSearch_GetRelatedVideos(
			string query,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SearchSortByEnum? sort,
			string source_filter_id,
			IEnumerable<string> source_whitelist,
			IEnumerable<string> source_blacklist
		)
		{
			Request request = new Request("search_getRelatedVideos", AccessKey, SharedSecret);
			request.AppendParameter("query", true, query);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SearchSortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("source_blacklist", false, source_blacklist);

			return request;
		}

		#endregion

		#region Source Calls

		/// <summary>
		///		Retrieves articles that are related to the specified source(s).
		/// </summary>
		/// <param name="source">The list of sources.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="include_image">Return one related scraped image.</param>
		/// <param name="include_scores">Return enhanced score data for every article, if available.</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSource_GetArticles(
			IEnumerable<string> source,
			SourceSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			bool? include_image,
			bool? include_scores
		)
		{
			Request request = new Request("source_getArticles", AccessKey, SharedSecret);
			request.AppendParameter(searchType == SourceSearchByEnum.SourceId ? "source_id" : "name", true, source);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter("include_image", false, include_image);
			request.AppendParameter("include_scores", false, include_scores);

			return request;
		}

		/// <summary>
		///		Retrieves information for the specified source(s).
		/// </summary>
		/// <param name="source">The list of sources.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSource_GetInfo(
			IEnumerable<string> source,
			SourceSearchByEnum searchType
		)
		{
			Request request = new Request("source_getInfo", AccessKey, SharedSecret);
			request.AppendParameter(searchType == SourceSearchByEnum.SourceId ? "source_id" : "name", true, source);

			return request;
		}

		/// <summary>
		///		Retrieves topics referenced in the articles published by the specified source(s).
		/// </summary>
		/// <param name="source">The list of sources.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="include_topic_type">Comma seperated list of topic types to include. (optional)</param>
		/// <param name="include_image">Return one thumbnail image for each topic. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestSource_GetTopics(
			IEnumerable<string> source,
			SourceSearchByEnum searchType,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			string include_topic_type,
			bool? include_image
		)
		{
			Request request = new Request("source_getTopics", AccessKey, SharedSecret);
			request.AppendParameter(searchType == SourceSearchByEnum.SourceId ? "source_id" : "name", true, source);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("include_topic_type", false, include_topic_type);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		#endregion

		#region Topic Calls

		/// <summary>
		///		Retrieves basic information for the specified topic.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="include_image">Return one related scraped image.</param>
		/// <param name="include_wikipedia_info">Return wikipedia abstract, if available.</param>
		/// <returns>
		///		An <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetInfo(
			string topic,
			TopicSearchByEnum searchType,
			bool? include_image,
			bool? include_wikipedia_info
		)
		{
			Request request = new Request("topic_getInfo", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("include_image", false, include_image);
			request.AppendParameter("include_wikipedia_info", false, include_wikipedia_info);

			return request;
		}

		/// <summary>
		///		Retrieves quotes that are said by the topic matching the specified topic.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="block_nsfw">Flag to indicate if content scored as obscene should be blocked. (optional)</param>
		/// <param name="source_blacklist">The list of Daylife source ids to exclude from returned results. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetQuotesBy(
			string topic,
			TopicSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			IEnumerable<string> source_whitelist,
			bool? block_nsfw,
			IEnumerable<string> source_blacklist
		)
		{
			Request request = new Request("topic_getQuotesBy", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_blacklist", false, source_blacklist);

			return request;
		}

		/// <summary>
		///		Creates a <see cref="Request"/> object to retrieve articles related to the
		///		specified topic.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="threshold">The minimum topic relevance score for returned item (1 to 9).</param>
		/// <param name="block_nsfw">Block obscene content. (optional)</param>
		/// <param name="source_blacklist">The list of sources to exclude.</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="include_image">Return a related article image, if available.</param>
		/// <param name="has_image">Return only articles with associated images.</param>
		/// <param name="include_scores">Return enhanced score data for every article, if available.</param>
		/// <param name="sliding_excerpt">Suppress sliding excerpts.</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetRelatedArticles(
			string topic,
			TopicSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			byte? threshold,
			bool? block_nsfw,
			IEnumerable<string> source_blacklist,
			IEnumerable<string> source_whitelist,
			bool? include_image,
			bool? has_image,
			bool? include_scores,
			bool? sliding_excerpt
		)
		{
			Request request = new Request("topic_getRelatedArticles", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("threshold", false, threshold);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("include_image", false, include_image);
			request.AppendParameter("has_image", false, has_image);
			request.AppendParameter("include_scores", false, include_scores);
			request.AppendParameter("sliding_excerpt", false, sliding_excerpt);

			return request;
		}

		/// <summary>
		///		Creates a <see cref="Request"/> object to retrieve images related to the
		///		specified topic.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="min_topic_image_confidence">The minimum threshold for the topic to image relevance.</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetRelatedImages(
			string topic,
			TopicSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			TopicImageConfidenceEnum? min_topic_image_confidence
		)
		{
			Request request = new Request("topic_getRelatedImages", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter<TopicImageConfidenceEnum>("min_topic_image_confidence", false, min_topic_image_confidence);

			return request;
		}

		/// <summary>
		///		Retrieves quotes from articles that contain the specified topic.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="require_speaker">The quotes returned must have a known speaker. (optional)</param>
		/// <param name="speaker_topic_id">The list of topics that the quotes must be attributed to. (optional)</param>
		/// <param name="threshold">The minimum topic relevance score for returned item (1 to 9).</param>
		/// <param name="block_nsfw">Flag to indicate if content scored as obscene should be blocked. (optional)</param>
		/// <param name="source_blacklist">The list of Daylife source ids to exclude from returned results. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetRelatedQuotes(
			string topic,
			TopicSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			IEnumerable<string> source_whitelist,
			bool? require_speaker,
			IEnumerable<string> speaker_topic_id,
			byte? threshold,
			bool? block_nsfw,
			IEnumerable<string> source_blacklist
		)
		{
			Request request = new Request("topic_getRelatedQuotes", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("require_speaker", false, require_speaker);
			request.AppendParameter("speaker_topic_id", false, speaker_topic_id);
			request.AppendParameter("threshold", false, threshold);
			request.AppendParameter("block_nsfw", false, block_nsfw);
			request.AppendParameter("source_blacklist", false, source_blacklist);

			return request;
		}

		/// <summary>
		///		Creates a <see cref="Request"/> object to retrieve topics that appear in the same
		///		articles as the specified topic.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="threshold">The minimum topic relevance score for returned item (1 to 9).</param>
		/// <param name="source_blacklist">The list of Daylife source ids to exclude from returned results. (optional)</param>
		/// <param name="include_topic_type">The list of topic types to include.</param>
		/// <param name="include_image">Return one thumbnail image for each topic. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetRelatedTopics(
			string topic,
			TopicSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			IEnumerable<string> source_whitelist,
			byte? threshold,
			IEnumerable<string> source_blacklist,
			IEnumerable<string> include_topic_type,
			bool? include_image
		)
		{
			Request request = new Request("topic_getRelatedTopics", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("threshold", false, threshold);
			request.AppendParameter("source_blacklist", false, source_blacklist);
			request.AppendParameter("include_topic_type", false, include_topic_type);
			request.AppendParameter("include_image", false, include_image);

			return request;
		}

		/// <summary>
		///		Creates a <see cref="Request"/> object to retrieve related related to the
		///		specified topic.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <param name="limit">The number of results to be returned. (optional)</param>
		/// <param name="offset">The index offset of the first record to be returned. (optional)</param>
		/// <param name="sort">The sorting order. (optional)</param>
		/// <param name="source_filter_id">The source filter Id. Replaces the value set at the client level. (optional)</param>
		/// <param name="min_topic_video_confidence">The minimum threshold for the topic to video relevance.</param>
		/// <param name="source_whitelist">The list of sources to include. (optional)</param>
		/// <param name="source_blacklist">The list of sources to exclude.</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetRelatedVideos(
			string topic,
			TopicSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time,
			int? limit,
			int? offset,
			SortByEnum? sort,
			string source_filter_id,
			TopicVideoConfidenceEnum? min_topic_video_confidence,
			IEnumerable<string> source_whitelist,
			IEnumerable<string> source_blacklist
		)
		{
			Request request = new Request("topic_getRelatedVideos", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);
			request.AppendParameter("limit", false, limit);
			request.AppendParameter("offset", false, offset);
			request.AppendParameter<SortByEnum>("sort", false, sort);
			request.AppendParameter("source_filter_id", false, source_filter_id, SourceFilterId);
			request.AppendParameter<TopicVideoConfidenceEnum>("min_topic_image_confidence", false, min_topic_video_confidence);
			request.AppendParameter("source_whitelist", false, source_whitelist);
			request.AppendParameter("source_blacklist", false, source_blacklist);

			return request;
		}

		/// <summary>
		///		Retrieves a digest of the daily number of references for the specified topic
		///		identifier in mainstream news and blog sources.
		/// </summary>
		/// <param name="topic">The topic to search for.</param>
		/// <param name="searchType">The type of value to search by.</param>
		/// <param name="end_time">Limit the search to items dated less than or equal to this value. (optional)</param>
		/// <param name="start_time">Limit the search to items dated greater than or equal to this value. (optional)</param>
		/// <returns>
		///		A <see cref="Request"/> object.
		/// </returns>
		public Request CreateRequestTopic_GetTimeline(
			string topic,
			TopicSearchByEnum searchType,
			DateTimeOffset? end_time,
			DateTimeOffset? start_time
		)
		{
			Request request = new Request("topic_getTimeline", AccessKey, SharedSecret);
			request.AppendParameter(searchType == TopicSearchByEnum.TopicId ? "topic_id" : "name", true, topic);
			request.AppendParameter("end_time", false, DaylifeExtensions.TimestampFormat, end_time, DateTimeKind.Utc);
			request.AppendParameter("start_time", false, DaylifeExtensions.TimestampFormat, start_time, DateTimeKind.Utc);

			return request;
		}

		#endregion

		#region Private Methods

		private string BuildSignature(string coreInput)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append(AccessKey).Append(SharedSecret).Append(coreInput);

			MD5CryptoServiceProvider cryptoProvider = new MD5CryptoServiceProvider();
			byte[] buffer = cryptoProvider.ComputeHash(UnicodeEncoding.UTF8.GetBytes(sb.ToString()));
			sb = new StringBuilder(32);

			foreach (byte b in buffer)
			{
				sb.Append(b.ToString("x2"));
			}

			return sb.ToString();
		}

		#endregion
	}
}
